package org.gavin.core.advice;

import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.gavin.core.annotation.Safety;
import org.gavin.core.conf.SafetyFactory;
import org.gavin.core.constant.CommonConst;
import org.gavin.core.domain.R;
import org.gavin.core.enums.CommonStatus;
import org.gavin.core.enums.SafetyType;
import org.gavin.core.exception.ParamException;
import org.gavin.core.service.safety.SafetyAbstract;
import org.gavin.core.utils.JsonUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Objects;

/**
 * SafetyResponseBodyAdvice
 *
 * @author grl
 * @date 2024/1/4
 */
@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
@SuppressWarnings("unchecked")
public class SafetyResponseBodyAdvice implements ResponseBodyAdvice {

    private final HttpServletRequest request;

    private final SafetyFactory safetyFactory;

    @Override
    public boolean supports(MethodParameter methodParameter, Class converterType) {
        Safety process = methodParameter.getMethodAnnotation(Safety.class);
        return process != null && process.encode();
    }

    /**
     * 原controller要返回的内容
     *
     * @param body
     * @param methodParameter
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (body instanceof R result) {
            Object data = result.getData();
            if (data != null) {
                result.setData(getEncData(JsonUtils.toJsonString(data)));
                return result;
            }
        }
        return body;
    }

    private String getEncData(String data) {
        String type = request.getHeader(CommonConst.SAFETY_TYPE);
        checkHeader(type);
        SafetyType safetyType = SafetyType.valueOf(type);
        SafetyAbstract safety = safetyFactory.getSafety(safetyType);
        return safety.getEncrypt(data);
    }

    private void checkHeader(String type) {
        if (StringUtils.isBlank(type)) {
            throw ParamException.le(CommonStatus.LACK_HEADER_PARAM_ERROR, "SafetyResponse", CommonConst.SAFETY_TYPE);
        }
    }
}
